using System;
using System.Diagnostics;
using System.Globalization;

namespace Atomic.Libraries.Physics.Units
{
	[Serializable]
	[DebuggerDisplay("{DebuggerDisplay}")]
	public struct Pressure : IQuantity
	{
		private double value;

		private Pressure(double value)
		{
			this.value = value;
		}

		public static Pressure FromUnit(IUnitSystem system, double value)
		{
			if (system.EnergyScaling == 1.0 && system.LengthScaling == 1.0)
			{
				return new Pressure(value);
			}
			else
			{
				// http://en.wikipedia.org/w/index.php?title=International_System_of_Units&oldid=596637756#Derived_units
				return new Pressure(value / (system.EnergyScaling / (system.LengthScaling * system.LengthScaling * system.LengthScaling)));
			}
		}

		public static Pressure FromElectronVoltPerCubicAngstrom(double value)
		{
			return FromUnit(UnitSystem.AtomicSystem, value);
		}

		public static Pressure FromPascal(double value)
		{
			return FromUnit(UnitSystem.InternationalSystem, value);
		}

		public static Pressure FromGigaPascal(double value)
		{
			return FromUnit(UnitSystem.InternationalSystem, value * 1.0e9);
		}
		
		public static Pressure FromBar(double value)
		{
			return FromUnit(UnitSystem.InternationalSystem, value * 1.0e5);
		}

		public static Pressure FromKiloBar(double value)
		{
			return FromUnit(UnitSystem.InternationalSystem, value * 1.0e8);
		}

		public double ToUnit(IUnitSystem system)
		{
			if (system.EnergyScaling == 1.0 && system.LengthScaling == 1.0)
			{
				return value;
			}
			else
			{
				return value * system.EnergyScaling / (system.LengthScaling * system.LengthScaling * system.LengthScaling);
			}
		}

		public double ToElectronVoltPerCubicAngstrom()
		{
			return ToUnit(UnitSystem.AtomicSystem);
		}

		public double ToPascal()
		{
			return ToUnit(UnitSystem.InternationalSystem);
		}

		public double ToGigaPascal()
		{
			return ToPascal() * 1.0e-9;
		}

		public double ToBar()
		{
			return ToPascal() * 1.0e-5;
		}

		public double ToKiloBar()
		{
			return ToPascal() * 1.0e-8;
		}

		public static implicit operator double(Pressure value)
		{
			return value.ToUnit(UnitSystem.AtomicSystem);
		}

		public static implicit operator Pressure(double value)
		{
			return FromUnit(UnitSystem.AtomicSystem, value);
		}

		private string DebuggerDisplay
		{
			get
			{
				return string.Format(CultureInfo.InvariantCulture, "{0} eV/Å^3 = {1} GPa = {2} kbar", ToElectronVoltPerCubicAngstrom(), ToGigaPascal(), ToKiloBar());
			}
		}
	}
}
